var zxy = (function () {

    /* 
             !0 封装
    
             1.先把主要代码实现
             2.声明一个函数，把主要代码放入到函数中
             3.找函数中可变的值做参数
             4.调用，调试
     */

    /*
        !1.
        作用:获取标签的属性，并return标签的属性，在调用的时候可以用变量接收，例如：var a=getAttr(elem,attr);
        @parm(参数) {object}(类型)  elem
        @parm(参数) {string}(类型)  attr
       
    */

    function getAttr(elem, attr) {
        var a = elem[attr];
        return a;
    }


    /* 
     
     原理：自定义一个最大值(arr[0]),和数组中所有的数组进行比较，如果数组中的值比较大，max存储最大值
     !2.
        作用:获取数组,长度任意,并return数组里面数值的最大值，在调用的时候可以用变量接收，例如：var a=max(arr);
        @parm(参数) {arr}(类型)  arr
    
     */
    function max(arr) {
        var m = arr[0];
        for (var i = 0; i < arr.length; i++) {
            if (m < arr[i]) {
                m = arr[i];
            }
        }
        return m;
    }

    /* 
     
     原理：用window.getComputedStyle作为判断条件，对象，函数是真值，没有获取到为undefined,则在标准浏览器下输出标准的，在IE8以下输出IE模式下的。最后return属性。
     !3.  (兼容)
        作用:获取行内以外的样式，内嵌式和外部引入，w=elem.style.width;获取到的是行内的，但是行内以外的样式都是获取不到的。
        调用方式：var a=getStyle(elem,attr);
        @parm(参数) {object}(类型)  elem(标签)
        @parm(参数) {string}(类型)  attr(属性)
    
     */
    // function getStyle(elem,attr) {
    //     if (window.getComputedStyle) {
    //         var w = getComputedStyle(elem)[attr]; //变量不能. 要使用中括号
    //     } else {
    //         var w = elem.currentStyle[attr]; //变量不能. 要使用中括号
    //     }
    //     return w;
    // }
    //更简便的代码实现 
    function getStyle(elem, attr) {
        return window.getComputedStyle ? getComputedStyle(elem)[attr] : elem.currentStyle[attr];
    }



    /* 
        !4.有问题！！用的时候数值会跳动 已解决，可以正常调用
        购物车的实现，第一个参数为父元素li，第二个为元素名div总计，第三个为类名，每一个小计
        调用方式 例如:
           for (var i = 0; i <parent.length; i++) {
                btn(parent[i], elem, class1);
            }
        作用:代码复用
        @parm(参数) {object}(类型)  parent(标签父元素多个)
        @parm(参数) {object}(类型)  elem(标签名一个)
        @parm(参数) {object}(类型)  class1(类名，多个)
    */

    function btn(parent, elem, class1) {
        var oBtn1 = parent.getElementsByTagName("button")[0]; //-
        var oIn1 = parent.getElementsByTagName("input")[0]; //Button里的数值
        var oBtn2 = parent.getElementsByTagName("button")[1]; //+
        var oSp1 = parent.getElementsByTagName("span")[0]; //单价
        var oSp2 = parent.getElementsByTagName("span")[1]; //小计
        console.log(oSp2);

        var dSp1 = elem.getElementsByTagName("span")[0];
        oSp2.innerHTML = "0.00"; //字符串可以，但是放数字不可以。
        oIn1.style.width = "30px";
        oIn1.style.outline = "none";
        oIn1.style.textAlign = "center";
        oIn1.style.border = "none";

        function sums() {
            var s = 0;
            for (var i = 0; i < class1.length; i++) {
                s = (parseFloat(s) + parseFloat(class1[i].innerHTML)).toFixed(2);
            }
            return s;
        }

        oIn1.onmouseout = function () {
            oSp2.innerHTML = (parseFloat(oIn1.value) * parseFloat(oSp1.innerHTML)).toFixed(2);

        }
        oBtn1.onclick = function () {
            if (parseFloat(oIn1.value) > 0) {
                oIn1.value--;
                oSp2.innerHTML = (parseFloat(oIn1.value) * parseFloat(oSp1.innerHTML)).toFixed(2);
                dSp1.innerHTML = sums();
            }
        }
        oBtn2.onclick = function () {
            oIn1.value++;
            oSp2.innerHTML = (parseFloat(oIn1.value) * parseFloat(oSp1.innerHTML)).toFixed(2);
            dSp1.innerHTML = sums();
        }
    }


    /* 
     
     !5.运动框架
        作用:获取运动对象，步长，结束值，运动属性，例如1： 按钮.onclick = function () {
                move(obj, 10, 500, "top");
            }
            例如2：move(obj, 10, 500, "left");
        @parm(参数) {obj}(类型)     obj(标签)
        @parm(参数) {number}(类型)  tag
        @parm(参数) {number}(类型)  stopValue
        @parm(参数) {string}(类型)  attr
    
     */

    //让某一个元素以某种速度，往某个方向运动
    function move(obj, tag, stopValue, attr) { //运动对象，步长，结束值，运动属性
        //初始值 200 20 -初始值 8 500+
        tag = stopValue > parseInt(getStyle(obj, attr)) ? tag : -tag;
        clearInterval(obj.timer);
        obj.timer = setInterval(
            function () {
                var speed = parseInt(getStyle(obj, attr)) + tag;
                if (speed <= stopValue && tag < 0 || speed >= stopValue && tag > 0) {
                    speed = stopValue;
                }
                obj.style[attr] = speed + "px";
                if (speed == stopValue) {
                    clearInterval(obj.timer);
                }
            }, 30);
    }


    /* 
     
     !6. x到y之间的随机整数
        原理:公式为：
             大减小加1
             乘以随机数
             加上最小值
             向下取整
        作用: 获取x到y之间的随机整数。例如1： console.log(getRandom(2,8));
             
        @parm(参数) {number}(类型)  min
        @parm(参数) {number}(类型)  max
    
     */
    function getRandomXY(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }

    /* 
     
     !7. 
        原理:调用的时候获取父元素的标签，在js里面数组放对应的颜色，根据颜色的数组的长度生成多个button或者其他元素，然后给每个button或者其他元素添加对应的文字，点击对应的button或者其他元素，改变其背景颜色，或者父元素和其他元素的颜色。
    
        作用: 生成多个button或者其他的元素，点击对应的button或者其他元素，改变body的背景颜色，当然也可以改变父元素的，把代码里的 document.body.style.background = arr[this.index];改成 parent.style.background = arr[this.index];即可。如果点击事件改变为其他的，可以把这个替换 var oBtn=document.getElementsByTagName("button");里面的"button"，换成你想要点击的元素即可,还有就是 parent.innerHTML+="<button>颜色</button> ";也换成对应的元素即可。如果颜色想要换的话可以在arr数组换颜色和添加，但是添加颜色一定要再添加elem[添加颜色的下标]和对应的文字。
    
        @parm(参数) {object}(类型)  parent
    
        调用例子:
        -------html
         <div></div>
        -------js
          var oDiv = document.getElementsByTagName("div")[0];
          changeBackground(oDiv);
     */

    function changeBackground(parent) {
        var arr = ["skyblue", "gold", "tomato", "pink", "#ccc"]; //颜色
        var arr1 = ["天空蓝", "太阳金", "番茄橘", "少女粉", "简单色"]; //button里面的文字
        for (var j = 0; j < arr1.length; j++) {
            parent.innerHTML += "<button>" + arr1[j] + "</button> "; //改button文字，//初始button，一个button对应一个颜色，有多少个颜色就有多少个button。
        }
        var elem = document.getElementsByTagName("button");
        for (var i = 0; i < arr.length; i++) {
            elem[i].index = i;
            elem[i].onclick = function () {
                document.body.style.background = arr[this.index];
            }
        }
    }


    /* 
     
     !8.作用: 在elem(标签)内，生成num位字母和数字的随机数。
    
        @parm(参数) {object}(类型)  elem
        @parm(参数) {number}(类型)  num
        调用：
    
        例如：   
        ---html
        <div></div>
        ---js
        var oDiv = document.getElementsByTagName("div")[0];
        randomN(oDiv,4);
    
     */

    function randomN(elem, num) {
        var arr = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
        var n = "";
        for (var i = 0; i < num; i++) {
            n += arr[Math.floor(Math.random() * arr.length)];
        }
        elem.innerHTML = n;
        return elem.innerHTML;
    }

    /* 
     
     !8-2.作用: 生成num位字母和数字的随机数。
    
        @parm(参数) {number}(类型)  num
        调用：
    
        例如：   
        ---html
        <span></span>
        ---js
       var oSp = document.getElementsByTagName("span")[0];
            var oBtn = document.getElementsByTagName("button")[0];
            oBtn.onclick = function () {
                var s = randomCode(4);
                oSp.innerHTML = s;
            }
    
     */
    function randomCode(n) {
        var str = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
        var s = ""; //存放随机验证码
        for (var i = 0; i < n; i++) {
            s += str.charAt(Math.floor(Math.random() * str.length));
        }
        return s;
    }


    //轮播图1封装

    /* 
     
     !9.作用:生成轮播图。 有问题的封装！！ 已解决!! 可正常调用!!
        @parm(参数) {object}(类型)  parent
     
     */
    function lunB1(parent) {
        var oUl = parent.getElementsByTagName("ul")[0];
        var oSp = document.getElementsByTagName("span");
        var oSquare1 = document.getElementsByClassName("square")[0];
        var oSquare2 = document.getElementsByClassName("square")[1];
        var n = 0;
        var timer = setInterval(auto, 2000);

        function auto() {
            for (var i = 0; i < oSp.length; i++) {
                oSp[i].style.background = "#fff";
            }

            n++;
            if (n > 3) {
                n = 0;
            }

            oSp[n].style.background = "#ffcc93";
            move(oUl, 50, -700 * n, "left"); //0 -600 -1200 -1800
        }
        oUl.onmouseover = function () {
            clearInterval(timer);
        }

        oUl.onmouseout = function () {
            timer = setInterval(auto, 2000);
        }

        oSquare1.onclick = function () {
            // clearInterval(timer);
            n--;
            if (n < 0) {
                n = 3;
            }
            for (var k = 0; k < oSp.length; k++) {
                oSp[k].style.background = "#fff";
            }
            oSp[n].style.background = "#ffcc93";
            move(oUl, 50, -700 * n, "left");
        }
        oSquare1.onmouseover = function () {
            clearInterval(timer);
        }
        oSquare1.onmouseout = function () {
            timer = setInterval(auto, 2000);
        }
        oSquare2.onmouseover = function () {
            clearInterval(timer);
        }
        oSquare2.onmouseout = function () {
            timer = setInterval(auto, 2000);
        }
        oSquare2.onclick = function () {
            n++;
            if (n > 3) {
                n = 0;
            }
            for (var k = 0; k < oSp.length; k++) {
                oSp[k].style.background = "#fff";
            }
            oSp[n].style.background = "#ffcc93";
            move(oUl, 50, -700 * n, "left");
        }
        for (var j = 0; j < oSp.length; j++) { //这个放上面的话会导致第一次刷新不出来，无法进行移入事件。
            oSp[j].index = j;
            oSp[j].onmouseover = function () {
                clearInterval(timer);
                for (var k = 0; k < oSp.length; k++) {
                    oSp[k].style.background = "#fff";
                }
                this.style.background = "#ffcc93";
                move(oUl, 50, -700 * this.index, "left");
                n = this.index;
            }
        }
    }


    // !10 时间倒计时，传入未来的时间即可
    //例如   timeDiffer("2021,1,1,00:00:00");不能写成数字
    function timeDiffer(targetDate) {
        auto();
        setInterval(auto, 1000);

        function auto() {
            var currentDate = new Date();
            var futureDate = new Date(targetDate);
            var timeStamp = parseInt((Math.abs(futureDate - currentDate)) / 1000);
            var d = parseInt(timeStamp / 86400);
            var h = parseInt(timeStamp % 86400 / 3600);
            var tens = parseInt(timeStamp % 3600 / 60);
            var s = parseInt(timeStamp % 60);
            document.body.innerHTML = "距离元旦还有：" + setString(d) + "天" + setString(h) + "时" + setString(tens) + "分" + setString(s) + "秒";

            function setString(n) {
                if (n < 10) {
                    n = "0" + n;
                }
                return n;
            }
        }
    }


    // !11 创建标签 封装 都是字符串的参数

    function createElem(tagName, text) {
        var elem = document.createElement(tagName);
        elem.innerHTML = text;
        return elem;
    }



    // !12 事件绑定 封装  (兼容)

    // @parm(参数) {object}(类型)  obj   标签名 如：oDiv
    // @parm(参数) {string}(类型)  event 事件 如："click"
    // @parm(参数) {string}(类型)  callback 处理函数 如：fun
    // 这个参数已去掉 @parm(参数) {boolean}(类型)  boolean 是否捕获 如：true（捕获）/false（冒泡） 是否捕获 不兼容所有IE浏览器 所以把它去掉了，用阻止冒泡 用阻止事件冒泡 !14
    //调用 例如：bind(oDiv,"click",fun1);

    function bind(obj, event, callback) {
        if (obj.addEventListener) {
            obj.addEventListener(event, callback);
        } else {
            obj.attachEvent("on" + event, callback);
        }
    }

    // !13 事件取消 封装  (兼容)

    // @parm(参数) {object}(类型)  obj   标签名 如：oDiv
    // @parm(参数) {string}(类型)  event 事件 如："click"
    // @parm(参数) {string}(类型)  callback 处理函数 如：fun
    // 这个参数已去掉 @parm(参数) {boolean}(类型)  boolean 是否捕获 如：true（捕获）/false（冒泡） 是否捕获 不兼容所有IE浏览器 所以把它去掉了，用阻止事件冒泡 !14

    //调用 例如：unbind(oDiv,"click",fun1,true);

    function unbind(obj, event, callback) {
        if (obj.removeEventListener) {
            obj.removeEventListener(event, callback);
        } else {
            obj.detachEvent("on" + event, callback);
        }
    }

    // !14 阻止事件冒泡 (兼容)
    // @parm(参数) {string}(类型)  ev 事件

    // 在JavaScript中，默认是事件冒泡事件流机制，即当一个元素接收到事件的，会把接收到的事件依次传给他的父元素一直到window 
    // 阻止事件冒泡是指：子元素接收到事件以后，阻止子元素再给父元素传播事件。阻止事件的方法标准浏览器和ie浏览器有不同的表示方式：
    // 标准浏览器:ev.stopPropagation();
    // IE浏览器:ev.cancleBubble=true;

    //兼容处理为：
    function stopPropagation(ev) {
        if (ev.stopPropagation) {
            ev.stopPropagation();
        } else {
            ev.cancelBubble = true;
        }
    }

    // <!15 获取滚轮滚动信息-- >(兼容)
    // @parm(参数) {object}(类型)  ev 事件
    // 滚轮可以往上滚往下滚， 滚动方向的信息都存储在事件对象的一个属性中， 火狐和其他浏览器有不同的写法：
    // 标准、 IE： ev.wheelDelta 往上滚返回120， 往下滚返回 - 120
    // 火狐： ev.detail 往上 - 3， 下3


    // 函数封装 滚轮方向的兼容，上：120 下：-120
    function wheelDelta(ev) {
        if (ev.wheelDelta) {
            return ev.wheelDelta; //标准、IE
        } else {
            return ev.detail * -40; //firefox
        }
    }

    // !16 拖拽 封装 标签需要加定位，才可以获取到left和top值
    // @parm(参数) {object}(类型)  elem 标签

    function drag(elem) {
        elem.onmousedown = function (ev) {
            var ev = window.event || ev;
            var disX = ev.clientX - elem.offsetLeft;//鼠标到盒子的距离
            var disY = ev.clientY - elem.offsetTop;

            document.onmousemove = function (ev) {
                var ev = window.event || ev;
                var L = ev.clientX - disX;
                var T = ev.clientY - disY;
                elem.style.left = L + "px";
                elem.style.top = T + "px";
            }

            document.onmouseup = function () {
                document.onmousemove = elem.onmouseup = null;
                // 释放全局捕获
                if (elem.releaseCapture) {
                    elem.releaseCapture();
                }

            }
            //6.取消浏览器的默认行为
            //设置全局捕获
            if (elem.setCapture) {
                elem.setCapture();
            }
            return false;//标准未绑定的简单事件，return false即取消默认绑定
        }
    }

    // <!17 滚轮向上和向下-- >(兼容)
    // @parm(参数) {object}(类型)  ev 标签
    // @parm(参数) {function}(类型)  upFun 函数
    // @parm(参数) {function}(类型)  downFun 函数



    // 函数封装 滚轮方向的兼容，上：120 下：-120
    function mousewheel(elem, upFun, downFun) {
        //1.添加滚轮事件
        elem.onmousewheel = scroll;
        if (elem.addEventListener) {
            elem.addEventListener("DOMMouseScroll", scroll)
        }

        //2.声明一个滚动事件发生时调用的函数
        function scroll(ev) {
            var oEv = window.event || ev;
            //console.log(oEv.wheelDelta); //chrome ie
            //console.log(oEv.detail);//ff

            var tag = true; //上--true   下--false
            if (oEv.wheelDelta) {
                tag = oEv.wheelDelta > 0 ? true : false
            } else {
                tag = oEv.detail < 0 ? true : false
            }

            if (tag) {
                upFun();
            } else {
                downFun();
            }
        }
    }


    // !18 拖拽限制窗口边界 封装  标签需要加定位，才可以获取到left和top值
    // @parm(参数) {object}(类型)  elem 标签
    function dragLimit(elem) {
        elem.onmousedown = function (ev) {
            var ev = window.event || ev;
            var disX = ev.clientX - elem.offsetLeft;//鼠标到盒子的距离
            var disY = ev.clientY - elem.offsetTop;

            document.onmousemove = function (ev) {
                var ev = window.event || ev;
                var L = ev.clientX - disX;
                var T = ev.clientY - disY;
                var w = document.documentElement.clientWidth || document.body.clientWidth;
                if (L <= 0) {
                    L = 0;
                }
                if (L >= w - elem.offsetWidth) {
                    L = w - elem.offsetWidth;
                }
                var h = document.documentElement.clientHeight || document.body.clientHeight;
                if (T <= 0) {
                    T = 0;
                }
                if (T >= h - elem.offsetHeight) {
                    T = h - elem.offsetHeight;
                }
                elem.style.left = L + "px";
                elem.style.top = T + "px";
            }

            document.onmouseup = function () {
                document.onmousemove = elem.onmouseup = null;
                // 释放全局捕获
                if (elem.releaseCapture) {
                    elem.releaseCapture();
                }
            }
            //6.取消浏览器的默认行为
            //设置全局捕获
            if (elem.setCapture) {
                elem.setCapture();
            }
            return false;//标准未绑定的简单事件，return false即取消默认绑定
        }

    }

    //!19  任意物体属性运动
    function bufferMove(elem, attr, target, xs) {//elem:运动元素 attr:运动属性 target:目标值 xs:系数  xs越大，效果越慢
        clearInterval(elem.timer);
        elem.timer = setInterval(function () {
            //先获取当前的left
            if (attr == "opacity") {
                // target = target < 1  ? target* 100 :target;
                target = target * 100;
                var cur = parseInt(getStyle(elem, attr) * 100);
            } else {
                var cur = parseInt(getStyle(elem, attr));
            }
            var speed = (target - cur) / xs;//(目标值-当前值)/缩放比例
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

            if (cur == target) {
                clearInterval(elem.timer);
            }
            if (attr == "opacity") {
                target = target / 100;
                elem.style[attr] = (cur + speed) / 100;//attr 透明度不加单位
            } else {
                elem.style[attr] = cur + speed + "px";
            }
        }, 30)
    }


    // !20  碰撞检测 没有碰撞的时候返回false,碰撞返回true
    function knock(elem1, elem2) {
        var l1 = elem1.offsetLeft;
        var r1 = elem1.offsetLeft + elem1.offsetWidth;
        var t1 = elem1.offsetTop;
        var b1 = elem1.offsetTop + elem1.offsetHeight;

        var l2 = elem2.offsetLeft;
        var r2 = elem2.offsetLeft + elem2.offsetWidth;
        var t2 = elem2.offsetTop;
        var b2 = elem2.offsetTop + elem2.offsetHeight;

        if (l1 > r2 || r1 < l2 || t1 > b2 || b1 < t2) {
            return false;
        } else {
            return true;
        }
    }

    // !21 碰撞检测+拖拽限制窗口边界 封装  标签需要加定位，才可以获取到left和top值 
    // @parm(参数) {object}(类型)  elem 标签
    // @parm(参数) {object}(类型)  elem2 标签
    function dragLimKnock(elem, elem2) {//形参
        elem.onmousedown = function (ev) {
            var ev = window.event || ev;
            var disX = ev.clientX - elem.offsetLeft;//鼠标到盒子的距离
            var disY = ev.clientY - elem.offsetTop;

            document.onmousemove = function (ev) {
                var ev = window.event || ev;
                if (knock(elem, elem2)) {//实参
                    elem2.style.background = "black";
                } else {
                    elem2.style.background = "yellowgreen";
                }
                var L = ev.clientX - disX;
                var T = ev.clientY - disY;
                var w = document.documentElement.clientWidth || document.body.clientWidth;
                if (L <= 0) {
                    L = 0;
                }
                if (L >= w - elem.offsetWidth) {
                    L = w - elem.offsetWidth;
                }
                var h = document.documentElement.clientHeight || document.body.clientHeight;
                if (T <= 0) {
                    T = 0;
                }
                if (T >= h - elem.offsetHeight) {
                    T = h - elem.offsetHeight;
                }

                elem.style.left = L + "px";
                elem.style.top = T + "px";
            }

        }
        document.onmouseup = function () {
            document.onmousemove = elem.onmouseup = null;
        }
        function knock(elem1, elem2) {//形参
            var l1 = elem1.offsetLeft;
            var r1 = elem1.offsetLeft + elem1.offsetWidth;
            var t1 = elem1.offsetTop;
            var b1 = elem1.offsetTop + elem1.offsetHeight;

            var l2 = elem2.offsetLeft;
            var r2 = elem2.offsetLeft + elem2.offsetWidth;
            var t2 = elem2.offsetTop;
            var b2 = elem2.offsetTop + elem2.offsetHeight;

            if (l1 > r2 || r1 < l2 || t1 > b2 || b1 < t2) {
                return false;
            } else {
                return true;
            }
        }
    }

    //!22  完整运动函数 多物体多属性运动(已解决多个目标值可以达到)+回滚函数 attrs为对象
    /* 
    已解决多个目标值可以达到
          问题：不能所有的运动属性值都到达目标值
          原因：一个运动属性到达了目标点就把定时器停掉了
          解决：所有属性都到了目标点才能停
          */

    // 调用例子如下：
    // 1. ManyMove(oUl, { left: -700 }, 10);
    // 2. ManyMove(oUl, { left: -700 * n }, 10);
    // 3.  
    // oDiv.onclick = function () {
    //     bufferMove(oDiv, { "left":500 }, 5,function(){
    //         bufferMove(oDiv, { "top":500 },5)
    //     })
    // }
    // @parm(参数) {object}(类型)  elem 标签
    // @parm(参数) {object}(类型)  attrs 
    // @parm(参数) {number}(类型)  xs 
    // @parm(参数) {function}(类型)  callback 回调函数（可选参数）

    function manyMove(elem, attrs, xs, callback) {
        clearInterval(elem.timer)
        elem.timer = setInterval(function () {

            //a.假设所有属性都到了目标 
            var tag = true;
            //b.验证：挨个看，只要有一个没有到目标点  假设不成立  tag = false
            for (var attr in attrs) {//attr:width  height
                //4.获取当前值
                if (attr == "opacity") {
                    //目标需要放大100
                    attrs[attr] = attrs[attr] <= 1 ? attrs[attr] * 100 : attrs[attr];
                    var cur = parseInt(getStyle(elem, attr) * 100); //透明度的值太小，放大100倍处理
                } else {
                    var cur = parseInt(getStyle(elem, attr));
                }

                //5.计算速度 (目标值-当前值)/系数
                var speed = (attrs[attr] - cur) / xs;

                //6.像素取整
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

                //3.移动div
                if (attr == "opacity") {
                    elem.style[attr] = (cur + speed) / 100;  //透明度不加单位
                } else {
                    elem.style[attr] = cur + speed + "px";
                }

                //c.只要有一个没有到目标点  假设不成立  tag = false
                if (cur != attrs[attr]) {
                    tag = false;
                }
            }

            //d.通过tag的值，得出结论
            if (tag == true) {
                clearInterval(elem.timer);
                //两真为真，如果第一个为真，看第二个，如果第一个为假，第二个就不看
                callback && callback(); //callback：可选
            }
        }, 30);
    }



    //!23  未完成的封装  多物体运动+无缝隙轮播图
    function lunBo2() {
        var oBox = document.getElementsByTagName("div")[0];
        var oUl = oBox.getElementsByTagName("ul")[0];
        var oSp = document.getElementsByTagName("span");
        var oSquare1 = document.getElementsByClassName("square")[0];
        var oSquare2 = document.getElementsByClassName("square")[1];

        var n = 0;
        var timer = setInterval(auto, 5000);

        function auto() {
            for (var i = 0; i < oSp.length; i++) {
                oSp[i].style.background = "#fff";
            }
            n++;
            if (n > 4) {
                n = 1;
                oUl.style.left = "0px";
            }

            oSp[n == 4 ? 0 : n].style.background = "#ffcc93";
            ManyMove(oUl, { left: -700 * n }, 10);
        }

        oBox.onmouseover = function () {
            clearInterval(timer);
        }
        oBox.onmouseout = function () {
            timer = setInterval(auto, 2000);
        }
        for (var j = 0; j < oSp.length; j++) {//这个放上面的话会导致第一次刷新不出来，无法进行移入事件。
            oSp[j].index = j;
            oSp[j].onmouseover = function () {
                clearInterval(timer);
                for (var k = 0; k < oSp.length; k++) {
                    oSp[k].style.background = "#fff";
                }
                this.style.background = "#ffcc93";
                // move(oUl, 50, -700 * this.index, "left");
                ManyMove(oUl, { left: -700 * this.index }, 2);

                n = this.index;
            }
        }
    }


    // !24 表单用户名和密码验证  （面向对象）封装 
    // @parm(参数) {string}(类型)  elem1 标签
    // @parm(参数) {string}(类型)  elem2 标签
    function Check(elem1, elem2) {
        this.oIn = document.getElementsByTagName(elem1)[0];//输入框的内容
        this.oSp = document.getElementsByTagName(elem2)[0];//标签提示

        var that = this;
        this.init = function () {
            this.oIn.onchange = function () {
                that.checkUser();
            }
        }
        this.init();

        this.checkUser = function () {
            this.v = this.oIn.value;
            if (this.v.length > 18 || this.v.length < 6) {
                this.oSp.innerHTML = "长度应为6-18个字符";
                this.oSp.style.color = "#ffaaaa";
                this.oIn.style.border = "1px solid #ffaaaa";
            } else if (/^[^a-zA-Z]/.test(this.v)) {
                this.oSp.innerHTML = "必须以字母开头";
                this.oSp.style.color = "#ffaaaa";
                this.oIn.style.border = "1px solid #ffaaaa";
            } else if (/\W/.test(this.v)) {
                this.oSp.innerHTML = "非法字符，请使用字母、数字、下划线";
                this.oSp.style.color = "#ffaaaa";
                this.oIn.style.border = "1px solid #ffaaaa";
            } else {
                this.oSp.innerHTML = "恭喜，该邮箱可以注册";
                this.oSp.style.color = "#33a853";
                this.oIn.style.border = "1px solid #83aae9";
            }
        }
        this.oIn.focus();
    }


    /* ! 25
      *作用：请求后台数据
      *@parm {object} requests：请求对象的各种数据
      */

    //调用方式
    /* 
          zxy.ajax({
          "url": "http://edu.xqb.ink/api/courselist?limits=1",
          "type": "get",
          "success": function (res) {
              console.log(res);
          }
      })
    */
    function ajax(requests) {
        var xhr = new XMLHttpRequest();
        if (requests.type.toLowerCase() == "get") {
            var d = requests.data ? requests.url + "?" + requests.data : requests.url;
            xhr.open(requests.type, d, true);
            xhr.send();
        } else {
            xhr.open(requests.type, requests.url, true);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.send(requests.data);
        }
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4 && xhr.status == 200) {
                requests.success(JSON.parse(xhr.responseText));
            }
        }
    }


    //  !26 选项卡
    function TabSwitch(menus, items, type) {
        //1.获取标签的变量，作为属性
        this.menus = menus;
        this.items = items;
        //4.存储正确的this
        var that = this;

        //2.添加入口方法
        this.init = function () {
            for (var i = 0; i < this.menus.length; i++) {
                this.menus[i].index = i;
                this.menus[i][type] = function () {
                    //3.事件里面的代码，存放在一个方法中
                    that.changeItem(this.index);
                }
            }
        }
        this.init();


        //3.事件里面的代码，存放在一个方法中
        this.changeItem = function (index) {//var index
            for (var j = 0; j < this.items.length; j++) {
                this.items[j].style.display = "none";
                this.menus[j].className = "";
            }
            this.items[index].style.display = "block";
            this.menus[index].className = "active";
        }
    }

    /*  ！27 
        *作用：秒转换为  具体的时间格式
        *@parm {number} time：时间
        */
    function timeToString(time) {
        var h = parseInt(time / 3600);
        var m = parseInt(time % 3600 / 60);
        var s = parseInt(time % 60);
        return fullZero(h) + ":" + fullZero(m) + ":" + fullZero(s);
    }

    /*  ！28
    *作用：补0
    *@parm {number} time：时间
    */
    function fullZero(time) {
        return time >= 10 ? time : "0" + time;
    }
    /*  ！29
      *作用：获取数据类型
      *@parm {data} 
      */
    function getType(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
    /*  ！30 
//   *作用：深拷贝
//   *@parm {obj}  引用数据类型
//   */
    function deepCopy(obj) {
        if (getType(obj) == "Array") {
            var res = [];
        } else if (getType(obj) == "Object") {
            var res = {};
        } else {
            return obj;
        }
        for (key in obj) {
            if (getType(obj[key]) == "Object" || getType(obj[key]) == "Array") {
                res[key] = deepCopy(obj[key]);
            } else {
                res[key] = obj[key];
            }
        }
        return res;
    }

    return {
        "getAttr": getAttr,
        "max": max,
        "getStyle": getStyle,
        "btn": btn,
        "move": move,
        "getRandomXY": getRandomXY,
        "changeBackground": changeBackground,
        "randomN": randomN,
        "randomCode": randomCode,
        "lunB1": lunB1,
        "timeDiffer": timeDiffer,
        "createElem": createElem,
        "bind": bind,
        "unbind": unbind,
        "stopPropagation": stopPropagation,
        "wheelDelta": wheelDelta,
        "drag": drag,
        "mousewheel": mousewheel,
        "dragLimit": dragLimit,
        "bufferMove": bufferMove,
        "knock": knock,
        "dragLimKnock": dragLimKnock,
        "manyMove": manyMove,
        "lunBo2": lunBo2,
        "Check": Check,
        "ajax": ajax,
        "TabSwitch": TabSwitch,
        "timeToString": timeToString,
        "fullZero": fullZero,
        "getType": getType,
        "deepCopy": deepCopy
    }
})()